"use strict";

const {Service} = require("egg");
const {Question, Exam} = require("../entity/myentity");

class questionService extends Service {
  /**
   * 连带答案一起创建题目
   * todo:待测试
   * @param {Question} question 题目
   * @param {QuestionAnswer[]} answerList 答案列表
   * @param {Tag[]} tags 题目标签
   * @param {number} u_id 用户id
   */
  async addWithAnswer(question, answerList, tags, u_id) {
    const {app} = this;
    const conn = await app.mysql.beginTransaction();
    try {
      /**
       * 查询所属考试
       * @type {Exam}
       */
      const exam = await conn.get("exam", {id: question.e_id});
      const insertRes = await conn.insert("question", question);
      const q_id = insertRes.insertId;
      /**
       * 查询刚刚创建的question用于返回
       * @type {Question}
       */
      const queryQuestion = await conn.get("question", {
        id: q_id,
      });

      app.logger.info("创建题目完成，开始插入答案")
      //console.log(answerList)
      //批量添加答案
      //fixme:待修复只添加了一个答案的bug
      for (let i in answerList) {
        let answer = answerList[i];

        answer.q_id = queryQuestion.id;
        await conn.insert('q_answer', answer);
      }
      app.logger.info("添加答案完成，开始添加tag")
      //console.log(tags)
      //批量添加题目的tag
      for (let i in tags) {
        let t = tags[i]
        /**
         * 先查询该tag是否存在，如果不存在则先创建
         * @type {Tag|null}
         */
        let queryTag = await conn.get('tag', {name: t.name})
        if (queryTag == null) {
          await conn.insert('tag', {name: t.name})
          queryTag = await conn.get('tag', {name: t.name})
        }
        //关联题目与tag
        await conn.insert('q_tag', {q_id: q_id, t_id: queryTag.id})
      }
      app.logger.info(`用户${u_id}创建了题目id${insertRes.insertId}`);

      await conn.commit();
      return {suc: true, msg: "创建题目成功"};
    } catch (error) {
      await conn.rollback();
      app.logger.error(error);
      return {suc: false, msg: error};
    }
  }

  /**
   * 连带答案一起更新题目
   * fixme:需要更新
   * @param {Question} question 题目
   * @param {QuestionAnswer[]} answerList 答案列表
   * @param {number} u_id 用户id
   */
  async updateWithAnswer(question, answerList, u_id) {
    const {app} = this;
    const conn = await app.mysql.beginTransaction();
    try {
      /**
       * 查询所属考试
       * @type {Exam}
       */
      const exam = await conn.get("exam", {id: question.e_id});
      /**
       * 验证用户是不是该班级的老师
       * @type {UserClass}
       */
      const queryTeacher = await conn.get("u_class", {
        c_id: exam.c_id,
        u_id: u_id,
        isTeacher: true,
      });
      /**
       * 查询旧的question留以备用
       * @type {Question}
       */
      const oldQuestion = await conn.get("question", {id: question.id})

      if (queryTeacher == null) {
        app.logger.error(`用户${u_id}不是班级${exam.c_id}的老师，拒绝插入数据`);
        await conn.rollback();
        return {suc: false, msg: "只有班级的老师可以创建题目"};
      }
      await conn.update("question", question);
      app.logger.info(`用户${u_id}修改了题目id${question.id}`);

      //批量更新答案
      for (let i in answerList) {
        let answer = answerList[i];
        //console.log(answer)
        await conn.update('q_answer', answer);
      }

      //更新考试总分
      let oldExamScore = exam.total_score;
      let oldQuestionScore = oldQuestion.score
      let newScore = parseInt(oldExamScore) - parseInt(oldQuestionScore) + parseInt(question.score);
      await conn.update("exam", {id: exam.id, total_score: newScore});

      await conn.commit();
      return {suc: true, msg: "连带答案更新题目成功"};
    } catch (error) {
      await conn.rollback();
      app.logger.error(error);
      return {suc: false, msg: error};
    }
  }

  /**
   * 删除一个题目
   * @param {number} id 题目id
   * @param {number} u_id 删除人的id
   * @returns
   */
  async del(id, u_id) {
    const {app} = this;
    try {
      //查询要删除的题目
      const question = app.mysql.get("question", {id: id});
      //查询题目所属考试
      const exam = await app.mysql.get("exam", {id: question.e_id});
      /*      //验证用户是不是该班级的老师
            const queryTeacher = await conn.get("u_class", {
              c_id: exam.c_id,
              u_id: u_id,
              isTeacher: true,
            });
            if (queryTeacher == null) {
              ctx.logger.error(`用户${u_id}不是班级${exam.c_id}的老师，拒绝删除数据`);
              return {suc: false, msg: "只有班级的老师可以删除题目"};
            }*/
      await app.mysql.delete("question", {id: id});
      app.logger.info(`用户${u_id}删除了题目id${id}`);
      return {suc: true, msg: "删除题目成功"};
    } catch (error) {
      app.logger.error(error);
      return {suc: false, msg: error};
    }
  }

  /**
   * 批量获取question
   * @param {Question} question
   */
  async get(question) {
    const {app, ctx} = this;
    try {
      const query = await app.mysql.select("question", {where: question});
      //ctx.logger.info(query)
      //console.log(query.length);
      return {data: query, msg: "查询题目成功", suc: true};
    } catch (error) {
      ctx.logger.error(error);
      return {suc: false, msg: error};
    }
  }

  /**
   * 获取全部question
   */
  async getAll() {
    const {app, ctx} = this;
    try {
      const query = await app.mysql.select("question");
      return {data: query, msg: "查询全部题目成功", suc: true};
    } catch (error) {
      ctx.logger.error(error);
      return {suc: false, msg: error};
    }
  }

  /**
   * 批量将题目与考试绑定
   * @param {number}e_id
   * @param {Question[]} questionList
   */
  async bindExam(e_id,questionList){
    const {mysql,logger} = this.app
    const conn = await mysql.beginTransaction()
    //console.log("bindExam")
    try {
      for(let i in questionList){
        let q = questionList[i]
        //如果已经绑定，则直接跳过
        let query = await conn.get("e_question",{e_id:e_id,q_id:q.id})
        if(query != null){
          continue
        }
        await conn.insert("e_question",{e_id:e_id,q_id:q.id})
      }
      logger.info(`批量绑定考试${e_id}的题目`)
      await conn.commit()
      return {suc:true,msg:"添加成功"}
    }catch (e){
      await conn.rollback();
      logger.error(e);
      return {suc: false, msg: e};
    }
  }

  /**
   * 批量将题目与考试解除绑定
   * @param {number}e_id
   * @param {Question[]} questionList
   */
  async unbindExam(e_id,questionList){
    const {mysql,logger} = this.app
    const conn = await mysql.beginTransaction()
    //console.log("unbindExam")
    try {
      for(let i in questionList){
        let q = questionList[i]
        //如果本来就没有绑定，则直接跳过
        let query = await conn.get("e_question",{e_id:e_id,q_id:q.id})
        if(query == null){
          continue
        }
        console.log(query)
        await conn.delete("e_question",{e_id:e_id,q_id:q.id})
      }
      logger.info(`批量解绑考试${e_id}的题目`)
      await conn.commit()
      return {suc:true,msg:"解绑"}
    }catch (e){
      await conn.rollback();
      logger.error(e);
      return {suc: false, msg: e};
    }
  }


  /**
   * 清空一个考试的全部题目
   * @param {number} e_id 考试id
   */
  async clearExamQuestion(e_id){
    const {mysql,logger} = this.app
    const conn = await mysql.beginTransaction()
    try {
      await conn.delete("e_question",{e_id:e_id})
      await conn.commit()
      logger.info("删除了考试"+e_id+"的全部题目")
      return {suc:true,msg:"添加成功"}
    }catch (e){
      await conn.rollback();
      logger.error(e);
      return {suc: false, msg: e};
    }
  }

  /**
   * 获取考试的全部题目
   * @param {number} e_id 考试id
   */
  async getQuestionByExam(e_id){
    const {mysql,logger} = this.app
    try {
      let result = []
      /**@type{ExamQuestion[]} */
      let query = await mysql.select("e_question",{where:{e_id}})
      //console.log(query)
      for(let i in query){
        let q = await mysql.get("question",{id:query[i].q_id})
        if(q != null){
          result.push(q)
        }
      }
      logger.info("查询了考试"+e_id+"的全部题目")
      return {suc:true,msg:"添加成功",data:result}
    }catch (e){
      logger.error(e);
      return {suc: false, msg: e};
    }
  }

  /**
   * 根据输入的字段分别查询内容、tag、发布者
   * @param {string} searchInput 用户输入的字段
   */
  async search(searchInput){
    //如果什么都没输入则直接返回
    if(searchInput==="" || searchInput===null){
      return {suc:true,data:undefined,msg:"没有输入数据"}
    }
    const {mysql,logger} = this.app
    const contentResult = []
    const tagResult = []
    const userResult = []
    /** @type {Question[]}*/
    const otherResult = []

    const conn = await mysql.beginTransaction()
    try {

      /**
       * 获取到全部的Question
       * @type {Question[]}
       */
      let all = await conn.select("question")
      for(let i in all){
        let q = all[i]
        //如果题目的content包含搜索内容则加入contentResult
        if(q.content.includes(searchInput)){
          contentResult.push(q)
        }
        //如果搜索内容包含题目的content则加入otherResult（你可能想搜）
        if(searchInput.includes(q.content)){
          otherResult.push(q)
        }

        //查询tag
        /**@type{QuestionTag[]} */
        let tagQuery = await conn.select("q_tag",{where:{q_id:q.id}})
        let tagInclude = false
        let tagOtherInclude = false
        for (let j in tagQuery){
          /**@type{Tag} */
          let t = await conn.get("tag",{id:tagQuery[j].t_id})
          //如果题目的标签包含搜索内容，则加入tagResult
          if(t.name.includes(searchInput)){
            tagInclude = true;
          }
          if(searchInput.includes(t.name)){
            //如果搜索内容包含标签且otherResult中不存在该记录，则加入otherResult
            let joinOther = true
            for(let i in otherResult){
              if(otherResult[i].id === q.id){
                joinOther = false
                break
              }
            }
            tagOtherInclude = joinOther;
          }
        }
        if(tagInclude){
          tagResult.push(q)
        }

        /**
         * 查询发布者
         * @type {User}
         */
        let user = await conn.get("user",{id:q.u_id})
        if(user.name.includes(searchInput)){
          userResult.push(q)
        }
      }
      logger.info(`根据${searchInput}查询了一些题目`)
      await conn.commit()
      return {suc:true,msg:"搜索成功",data:{contentResult,tagResult,userResult,otherResult}}
    }catch (e) {
      await conn.rollback()
      logger.error(e)
      return {suc:false,msg:e}
    }
  }

  /**
   * 根据标签随机获取指定数量的题目
   * @param {number} count 要获取的数量
   * @param {string} tagName 指定的题目标签
   */
  async randomGetByTag(count,tagName){
    const {mysql,logger} = this.app
    const {ctx} = this
    if(count <= 0 || count > 100){
      logger.error("randomGetByTag:不合法的输入")
      return {suc:false,msg:"不合法的数量输入！"}
    }
    /**@type {QuestionTag[]}*/
    let resultQuestions = []
    try {
      /**
       * 首先获取该tag的信息
       * @type {Tag}
       */
      let tag = await mysql.get("tag",{name:tagName})

      /**
       * 获取包含该tag的全部题目
       * @type {QuestionTag[]}
       */
      let allQuestionTag = await mysql.select("q_tag",{where:{t_id:tag.id}})
      /** @type{Question[]}*/
      let allQuestion = []
      for(let i in allQuestionTag){
        let q = await mysql.get("question",{id:allQuestionTag[i].q_id})
        if(q != null) allQuestion.push(q);
      }

      //如果找到该tag的全部题目数量比输入的数量还小，则直接打乱返回
      if(allQuestion.length <= count){
        allQuestion.sort(function() {
          return (0.5-Math.random());
        });
        logger.info(`请求随机${count}道题目，实际获取${allQuestion.length}道`)
        return {data:allQuestion,msg:'获取成功',suc:true}
      }

      //随机挑选题目
      let i = 0;
      while (i < count){
        //获取随机下标并将目标加入返回值，同时将原始数组中该项移除
        let randomIndex = ctx.helper.getRndInteger(0,allQuestion.length)
        resultQuestions.push(allQuestion[randomIndex])
        allQuestion.splice(randomIndex,1)
        i++
      }
      logger.info(`请求随机${count}道题目，实际获取${count}道`)
      return {data:resultQuestions,msg:"获取成功",suc:true}
    }catch (e){
      logger.error(e)
      return {suc:false,msg:e}
    }
  }

  /**
   * 获取包含某标签的全部题目
   * todo:待测试
   * @param {string} tagName
   */
  async getByTag(tagName) {
    //console.log(tagName)
    const {mysql, logger} = this.app
    try {
      const responseQuestion = []
      /**@type{Tag} */
      let queryTag = await mysql.get("tag",{name:tagName})
      if(queryTag==null){
        logger.error(`没有找到标签${tagName}`)
        return {suc:false,msg:`没有找到标签${tagName}`}
      }
      /**
       * 查询该标签的全部题目id
       * @type {QuestionTag[]}
       */
      let queryTagQuestionList = await mysql.select("q_tag",{where:{t_id:queryTag.id}})
      //循环查询全部题目
      for(let i in queryTagQuestionList){
        let q = await mysql.get("question",{id:queryTagQuestionList[i].q_id})
        if(q!=null){
          responseQuestion.push(q)
        }
      }
      logger.info(`查询${tagName}的全部题目`)
      return {suc:true,msg:"查询该tags的题目成功",data:responseQuestion}
    } catch (e) {
      logger.error(e)
      return {suc:false,msg:e}
    }
  }


  /**
   * 为题目添加一张图片
   * @param {string} src 图片路径
   * @param {number} q_id 图片id
   */
  async addImage(src, q_id) {
    const {app, ctx} = this;
    const conn = await app.mysql.beginTransaction();
    try {
      await conn.insert("q_image", {src: src, q_id: q_id});
      await conn.commit();
      ctx.logger.info(`创建了题目图片${src}`);
      return {msg: "创建题目图片成功", suc: true};
    } catch (error) {
      await conn.rollback();
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 删除题目的一张图片
   * @param {number} id 图片id
   */
  async delImage(id) {
    const {app, ctx} = this;
    try {
      await app.mysql.delete("q_image", {id: id});
      ctx.logger.info(`删除了图片${id}`);
      return {suc: true, msg: "删除图片成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 修改题目的图片的路径
   * @param {number} id 图片id
   * @param {string} src 新路径
   */
  async updateImage(id, src) {
    const {app, ctx} = this;
    try {
      await app.mysql.update("q_image", {id: id, src: src});
      ctx.logger.info(`修改了图片${id}`);
      return {suc: true, msg: "修改图片成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 获取一个题目的全部图片
   * @param {number} q_id 题目id
   */
  async getImage(q_id) {
    const {app, ctx} = this;
    try {
      let res = await app.mysql.select("q_image", {where: {q_id: q_id}});
      return {data: res, suc: true, msg: "查询题目图片成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 为题目添加一个答案
   * @param {string} answer 答案内容
   * @param {number} q_id 图片id
   */
  async addAnswer(answer, q_id) {
    const {app, ctx} = this;
    const conn = await app.mysql.beginTransaction();
    try {
      await conn.insert("q_answer", {answer: answer, q_id: q_id});
      await conn.commit();
      ctx.logger.info(`创建了题目答案${answer}`);
      return {msg: "创建题目图片答案", suc: true};
    } catch (error) {
      await conn.rollback();
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 删除题目的答案
   * @param {number} id 答案id
   */
  async delAnswer(id) {
    const {app, ctx} = this;
    try {
      await app.mysql.delete("q_answer", {id: id});
      ctx.logger.info(`删除了答案${id}`);
      return {suc: true, msg: "删除答案成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 修改题目的答案
   * @param {number} id 答案id
   * @param {string} answer 新内容
   */
  async updateAnswer(id, answer) {
    const {app, ctx} = this;
    try {
      await app.mysql.update("q_answer", {id: id, answer: answer});
      ctx.logger.info(`修改了答案${id}`);
      return {suc: true, msg: "修改答案成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }

  /**
   * 获取一个题目的全部答案
   * @param {number} q_id 题目id
   */
  async getAnswer(q_id) {
    const {app, ctx} = this;
    try {
      let res = await app.mysql.select("q_answer", {where: {q_id: q_id}});
      return {data: res, suc: true, msg: "查询答案成功"};
    } catch (error) {
      ctx.logger.error(error);
      return {msg: error, suc: false};
    }
  }
}

module.exports = questionService;
